//
//  CacheManager.m
//  XtuanMoive
//
//  Created by ppl on 14-11-19.
//  Copyright (c) 2014年 X团. All rights reserved.
//

#import "CacheManager.h"
#import "sqlite3.h"

#define CACHE_DB_NAME @"cache_share.db"
#define CACHE_TABLE_NAME @"cache_share"
#define CACHE_MAX_COUNT 100

@implementation CacheManager

//初始化数据库
+ (CacheManager *)sharedCacheManager
{
    static CacheManager *instance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        
        instance = [[self alloc] init];
        
        NSString *path = [instance dbFilePath];
        sqlite3 *db;
        
        if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
            
            BOOL isCreated = NO;
            sqlite3_stmt *stmt;
            
            NSString *sql = [NSString stringWithFormat:@"SELECT name FROM sqlite_master WHERE type='table' AND name='%@';", CACHE_TABLE_NAME];
            
            if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
                if (sqlite3_step(stmt) == SQLITE_ROW) {
                    isCreated = YES;
                }
                
                sqlite3_finalize(stmt);
            }
            
            if (!isCreated) {
                sql = [NSString stringWithFormat:@"CREATE TABLE %@(id TEXT PRIMARY KEY, data BLOB, time REAL, flag INTEGER);", CACHE_TABLE_NAME];
                
                if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
                    NSLog(@"创建表失败: %@", sql);
                }
            }
            
            sqlite3_close(db);
            
        } else {
            NSLog(@"打开数据库失败: %@", path);
        }
    });
    return instance;
}

//用以储存Data类型的数据 flag 为永久化即可
- (void)setCache:(NSString *)key value:(NSData *)value flag:(int)flag
{
    NSString *path = [self dbFilePath];
    sqlite3 *db;
    
    if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
        sqlite3_stmt *stmt;
        NSString *sql = [NSString stringWithFormat:@"SELECT count(*),min(time) FROM %@ WHERE flag=%d;", CACHE_TABLE_NAME, CacheFlagDefault];
        
        if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
            
            if (sqlite3_step(stmt) == SQLITE_ROW) {
                
                int count = sqlite3_column_int(stmt, 0);
                double time = sqlite3_column_double(stmt, 1);
                
                if (count >= CACHE_MAX_COUNT) {
                    sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE time<=%f and flag=%d;", CACHE_TABLE_NAME, time + 1, CacheFlagDefault];
                    
                    if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
                        NSLog(@"删除失败: %@", sql);
                    }
                }
            }
            
            sqlite3_finalize(stmt);
        }
        
        BOOL isExist = NO;
        sql = [NSString stringWithFormat:@"SELECT id FROM %@ WHERE id=?;", CACHE_TABLE_NAME];
        if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
            sqlite3_bind_text(stmt, 1, [key UTF8String], (int)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding], NULL);
            
            if (sqlite3_step(stmt) == SQLITE_ROW) {
                isExist = YES;
            }
            
            sqlite3_finalize(stmt);
        }
        
        if (isExist) {
            sql = [NSString stringWithFormat:@"UPDATE %@ set data=?,time=?,flag=? where id=?;", CACHE_TABLE_NAME];
            
            if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
                sqlite3_bind_blob(stmt, 1, [value bytes], (int)[value length], NULL);
                sqlite3_bind_double(stmt, 2, [[NSDate date] timeIntervalSince1970]);
                sqlite3_bind_int(stmt, 3, flag);
                sqlite3_bind_text(stmt, 4, [key UTF8String], (int)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding], NULL);
                
                if (sqlite3_step(stmt) != SQLITE_DONE) {
                    NSLog(@"更新数据失败: %@", sql);
                }
                
                sqlite3_finalize(stmt);
            }
        } else {
            sql = [NSString stringWithFormat:@"INSERT INTO %@(id,data,time,flag) VALUES(?,?,?,?);", CACHE_TABLE_NAME];

            if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
                sqlite3_bind_text(stmt, 1, [key UTF8String], (int)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding], NULL);
                sqlite3_bind_blob(stmt, 2, [value bytes], (int)[value length], NULL);
                sqlite3_bind_double(stmt, 3, [[NSDate date] timeIntervalSince1970]);
                sqlite3_bind_int(stmt, 4, flag);
                
                if (sqlite3_step(stmt) != SQLITE_DONE) {
                    NSLog(@"插入数据失败: %@", sql);
                }
                
                sqlite3_finalize(stmt);
            }
        }
        
        sqlite3_close(db);
    } else {
        NSLog(@"打开数据库失败: %@", path);
    }
}

//获取Cache
- (NSData *)cache:(NSString *)key timeout:(NSTimeInterval)timeout
{
    NSData *data = nil;
    NSString *path = [self dbFilePath];
    sqlite3 *db;
    
    if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
        sqlite3_stmt *stmt;
        NSString *sql = [NSString stringWithFormat:@"SELECT id,data,time FROM %@ WHERE id=?;", CACHE_TABLE_NAME];
        
        if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
            sqlite3_bind_text(stmt, 1, [key UTF8String], (int)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding], NULL);
            
            if (sqlite3_step(stmt) == SQLITE_ROW) {
                double time = sqlite3_column_double(stmt, 2);
                NSTimeInterval curTime = [[NSDate date] timeIntervalSince1970];
                
                if (timeout < 0 || curTime - time <= timeout) {
                    data = [NSData dataWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)];
                }
            }
            
            sqlite3_finalize(stmt);
        }
        
        sqlite3_close(db);
        
    } else {
        NSLog(@"打开数据库失败: %@", path);
    }
    
    return data;
}

//移除缓存
- (void)removeCache:(NSString *)key withType:(CacheManagerType)type {

    if (type == CacheManagerTypeSQL) {
        NSString *path = [self dbFilePath];
        sqlite3 *db;
        
        if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
            NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE id='%@';", CACHE_TABLE_NAME, key];
            
            if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
                NSLog(@"删除失败: %@", sql);
            }
            
            sqlite3_close(db);
        } else {
            NSLog(@"打开数据库失败: %@", path);
        }
    } else if (type == CacheManagerTypeSDWebImage) {

    }
}

//清除某一Key名的Cache
- (void)removeCache:(NSString *)key
{
    NSString *path = [self dbFilePath];
    sqlite3 *db;
    
    if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
        NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE id='%@';", CACHE_TABLE_NAME, key];
        
        if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
            NSLog(@"删除失败: %@", sql);
        }
        
        sqlite3_close(db);
    } else {
        NSLog(@"打开数据库失败: %@", path);
    }
}

//清除所有数据库
- (void)clear
{
    NSString *path = [self dbFilePath];
    sqlite3 *db;
    
    if (sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
        NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@;", CACHE_TABLE_NAME];
        
        if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
            NSLog(@"清除失败: %@", sql);
        }
        
        sqlite3_close(db);
    } else {
        NSLog(@"打开数据库失败: %@", path);
    }
}

- (NSString *)dbFilePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [paths objectAtIndex:0];
    return [documentsDir stringByAppendingPathComponent:CACHE_DB_NAME];
}

@end
